/* * Copyright 2015 Hauke Oldsen * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package de.gebatzens.sia.data; import android.content.Context; import android.util.JsonReader; import android.util.JsonWriter; import android.util.Log; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import de.gebatzens.sia.SIAApp; import de.gebatzens.sia.R; import de.gebatzens.sia.fragment.RemoteDataFragment; public class Subst extends ArrayList<Subst.Entry> { public Date date; public List<String> special = new ArrayList<>(); private List<String> classes, lessons; public Subst() { } public String getWeekday() { return new SimpleDateFormat("EEEE").format(date); } public static class GGPlans extends ArrayList<Subst> implements RemoteDataFragment.RemoteData { public Throwable throwable; public Date loadDate; /** * true, if this data was loaded from storage rather than downloaded */ public boolean isLocal; @Override public Throwable getThrowable() { return throwable; } @Override public void save() { SIAApp.SIA_APP.preferences.edit().putLong("substLoadDate", loadDate.getTime()).commit(); String[] list = SIAApp.SIA_APP.fileList(); for(String s : list) { if (s.startsWith("schedule")) { SIAApp.SIA_APP.deleteFile(s); } } for(int i = 0; i < size(); i++) get(i).save("schedule" + i); } @Override public boolean load() { isLocal = true; loadDate = new Date(SIAApp.SIA_APP.preferences.getLong("substLoadDate", new Date().getTime())); clear(); try { for(int i = 0; ; i++) { Subst plan = new Subst(); plan.load("schedule" + i); add(plan); } } catch(FileNotFoundException e) { if(size() == 0) Log.w("ggvp", "Subst file does not exist"); } catch(Exception e) { e.printStackTrace(); } return size() > 0; } public Subst getPlanByDate(Date d) { for(Subst plan : this) if(plan.date.equals(d)) return plan; return null; } public boolean shouldRecreateView(GGPlans newPlans) { if(size() != newPlans.size()) return true; for (int i = 0; i < newPlans.size(); i++) { if (!newPlans.get(i).date.equals(this.get(i).date) || newPlans.get(i).size() != this.get(i).size() || newPlans.get(i).special.size() != this.get(i).special.size()) return true; } return false; } public List<String> getAllClasses() { Set<String> cl = new HashSet<>(); for(Subst plan : this) { cl.addAll(plan.getAllClasses()); } ArrayList<String> list = new ArrayList<>(); list.addAll(cl); return list; } } public void load(String file) throws Exception { clear(); special.clear(); InputStream in = SIAApp.SIA_APP.openFileInput(file); JsonReader reader = new JsonReader(new InputStreamReader(in)); reader.beginObject(); while(reader.hasNext()) { String name = reader.nextName(); switch (name) { case "date": date = new Date(reader.nextLong()); break; case "messages": reader.beginArray(); while (reader.hasNext()) { special.add(reader.nextString()); } reader.endArray(); break; case "entries": reader.beginArray(); while (reader.hasNext()) { reader.beginObject(); Entry e = new Entry(); e.date = date; while (reader.hasNext()) { String name2 = reader.nextName(); switch (name2) { case "class": e.clazz = reader.nextString(); break; case "lesson": e.lesson = reader.nextString(); break; case "teacher": e.teacher = reader.nextString(); break; case "subject": e.subject = reader.nextString(); break; case "comment": e.comment = reader.nextString(); break; case "type": e.type = reader.nextString(); break; case "room": e.room = reader.nextString(); break; case "repsub": e.repsub = reader.nextString(); break; default: reader.skipValue(); break; } } add(e); reader.endObject(); } reader.endArray(); break; default: reader.skipValue(); break; } } reader.endObject(); reader.close(); } public void save(String file) { Log.w("ggvp", "Saving " + file); try { OutputStream out = SIAApp.SIA_APP.openFileOutput(file, Context.MODE_PRIVATE); JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8")); writer.setIndent(" "); writer.beginObject(); writer.name("date").value(date.getTime()); writer.name("messages"); writer.beginArray(); for(String s : special) writer.value(s); writer.endArray(); writer.name("entries"); writer.beginArray(); for(Entry e : this) { writer.beginObject(); writer.name("class").value(e.clazz); writer.name("lesson").value(e.lesson); writer.name("teacher").value(e.teacher); writer.name("subject").value(e.subject); writer.name("comment").value(e.comment); writer.name("type").value(e.type); writer.name("room").value(e.room); writer.name("repsub").value(e.repsub); writer.endObject(); } writer.endArray(); writer.endObject(); writer.close(); } catch(Exception e) { e.printStackTrace(); } } public List<String> getAllClasses() { if(classes == null) { classes = new ArrayList<>(); for (Entry e : this) { if (!classes.contains(e.clazz)) { classes.add(e.clazz); } } } return classes; } public List<String> getAllLessons() { if(lessons == null) { lessons = new ArrayList<>(); for (Entry e : this) { if (!lessons.contains(e.lesson)) { lessons.add(e.lesson); } } Collections.sort(lessons, new Comparator<String>() { @Override public int compare(String lhs, String rhs) { try { int l1 = Integer.parseInt(lhs); int l2 = Integer.parseInt(rhs); return l1 - l2; } catch (Exception e) { Log.d("ggvp", "Lesson parsing failed " + e.getMessage()); } return lhs.compareTo(rhs); } }); } return lessons; } @Override public boolean equals(Object o) { if(o instanceof Subst) { Subst plan = (Subst) o; return super.equals(plan) && plan.date.equals(date) && plan.special.equals(special); } else return false; } public Subst filter(Filter.FilterList flist) { Subst list = new Subst(); list.date = date; for(Entry e : this) { if(flist.matches(e)) list.add(e); } Collections.sort(list, new Comparator<Entry>() { @Override public int compare(Entry lhs, Entry rhs) { try { int l1 = Integer.parseInt(lhs.lesson); int l2 = Integer.parseInt(rhs.lesson); return l1 - l2; } catch(Exception e) { Log.d("ggvp", "Lesson parsing failed " + e.getMessage()); } return lhs.lesson.compareTo(rhs.lesson); } }); return list; } public static class Entry implements Filter.Filterable, Shareable { public String type; public String clazz; public String missing = ""; public String teacher = ""; public String subject = ""; public String repsub = ""; public String comment = ""; public String lesson = ""; public String room = ""; public Date date; public boolean markedForSharing = false; private String classAN; private String teacherAN; private String subjectAN; private String lessonAN; private String commentAN; public String getClassAN() { if(classAN == null) classAN = SIAApp.deleteNonAlphanumeric(clazz); return classAN; } public String getTeacherAN() { if(teacherAN == null) teacherAN = SIAApp.deleteNonAlphanumeric(teacher); return teacherAN; } public String getSubjectAN() { if(subjectAN == null) subjectAN = SIAApp.deleteNonAlphanumeric(subject); return subjectAN; } public String getLessonAN() { if(lessonAN == null) lessonAN = SIAApp.deleteNonAlphanumeric(lesson); return lessonAN; } public String getCommentAN() { if(commentAN == null) commentAN = SIAApp.deleteNonAlphanumeric(comment); return commentAN; } @Override public boolean equals(Object o) { if(o instanceof Entry) { Entry e = (Entry) o; return e.type.equals(type) && e.clazz.equals(clazz) && e.subject.equals(subject) && e.teacher.equals(teacher) && e.comment.equals(comment) && e.lesson.equals(lesson) && e.room.equals(room) && e.repsub.equals(repsub); } else return false; } @Override public String toString() { return "Entry[" + type + " " + clazz + " " + subject + " " + teacher + " " + comment + " " + lesson + " " + room + " " + repsub + "]"; } @Override public void setMarked(boolean m) { markedForSharing = m; } @Override public boolean isMarked() { return markedForSharing; } @Override public String getShareContent() { int id; if(teacher.equals("")) { if(room.equals("")) { return SIAApp.SIA_APP.getResources().getString(R.string.share_content_base, this.type, this.clazz, this.lesson); } else { return SIAApp.SIA_APP.getResources().getString(R.string.share_content_room, this.type, this.clazz, this.lesson, this.room); } } else { if(room.equals("")) { return SIAApp.SIA_APP.getResources().getString(R.string.share_content_teacher, this.type, this.clazz, this.teacher, this.lesson); } else { return SIAApp.SIA_APP.getResources().getString(R.string.share_content_teacher_room, this.type, this.clazz, this.teacher, this.lesson, this.room); } } } @Override public Date getDate() { return date; } public void unify() { Matcher task = Pattern.compile("task (.*)").matcher(comment); switch (type) { case "entf": type = SIAApp.SIA_APP.getString(R.string.canceled); if (task.find()) comment = SIAApp.SIA_APP.getString(R.string.task_through) + " " + task.group(1); break; case "eva": type = SIAApp.SIA_APP.getString(R.string.work_autonomous); if (task.find()) comment = SIAApp.SIA_APP.getString(R.string.task_through) + " " + task.group(1); break; case "teacher": type = SIAApp.SIA_APP.getString(R.string.substitute); if (task.find()) comment = SIAApp.SIA_APP.getString(R.string.task_through) + " " + task.group(1); break; case "exam": type = SIAApp.SIA_APP.getString(R.string.exam); break; case "lesson": type = SIAApp.SIA_APP.getString(R.string.lesson); break; case "shifted": { type = SIAApp.SIA_APP.getString(R.string.canceled) + " / " + SIAApp.SIA_APP.getResources().getString(R.string.shift); Matcher m = Pattern.compile("shift (\\S*) (\\S*)").matcher(comment); if (m.find()) { String sdates = m.group(1); Date sdate = sdates.contains("today") ? date : parseDate(sdates); String lesson = m.group(2); if (sdate == null) comment = ""; else if (sdate.equals(date)) comment = SIAApp.SIA_APP.getString(R.string.shifted_to_today) + " " + lesson + ". " + SIAApp.SIA_APP.getString(R.string.lhour); else comment = SIAApp.SIA_APP.getString(R.string.shifted_to) + " " + new SimpleDateFormat("EEE").format(sdate) + ", " + DateFormat.getDateInstance().format(sdate) + " " + lesson + ". " + SIAApp.SIA_APP.getString(R.string.lhour); } break; } case "instead": { type = SIAApp.SIA_APP.getString(R.string.substitute) + " / " + SIAApp.SIA_APP.getResources().getString(R.string.shift); Matcher m = Pattern.compile("instead (\\S*) (\\S*)").matcher(comment); if (m.find()) { String idates = m.group(1); Date idate = idates.contains("today") ? date : parseDate(idates); String lesson = m.group(2); if (idate == null) comment = ""; else if (idate.equals(date)) comment = SIAApp.SIA_APP.getString(R.string.instead_of) + " " + lesson + ". " + SIAApp.SIA_APP.getString(R.string.lhour); else comment = SIAApp.SIA_APP.getString(R.string.instead_of) + " " + new SimpleDateFormat("EEE").format(idate) + ", " + DateFormat.getDateInstance().format(idate) + " " + lesson + ". " + SIAApp.SIA_APP.getString(R.string.lhour); } break; } case "supervision": type = SIAApp.SIA_APP.getString(R.string.supervision); break; case "lunch": type = SIAApp.SIA_APP.getString(R.string.lunch); break; case "subst": type = SIAApp.SIA_APP.getString(R.string.substitute); if (task.find()) comment = SIAApp.SIA_APP.getString(R.string.task_through) + " " + task.group(1); break; } if(subject.isEmpty() && !repsub.isEmpty()) subject = "→ " + repsub; else if(!subject.isEmpty() && !repsub.isEmpty() && !subject.equals(repsub)) subject += " → " + repsub; comment = comment.replace(" ", " "); } public static String translateSubject(String s) { String t = SIAApp.SIA_APP.subjects.get(s.toLowerCase()); if(t == null) return s; else return t; } @Override public int compareTo(Shareable shareable) { if(shareable instanceof Entry) { return lesson.compareTo(((Entry) shareable).lesson); } return 0; } } public static Date parseDate(String date) { SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd"); try { return fmt.parse(date); } catch(Exception e) { Log.w("ggvp", "WARNING: Invalid date " + date); return null; } } }